<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8">
    <title>Sucha's Blog - Archive for April, 2020</title>
    <meta name="generator" content="MarkdownProjectCompositor.lua">
    <meta name="author" content="Sucha">
    <meta name="keywords" content="suchang, programming, Linux, Lua">
    <meta name="description" content="Sucha's blog">
    <link rel="shortcut icon" href="../images/ico.png">
    <link rel="stylesheet" type="text/css" href="../styles/blog.css">
    <link rel="stylesheet" type="text/css" href="../styles/prism.min.css">
    <style id="site_theme"></style>
  </head>
  <body>
    <div id="body">
      <div id="text">
	   <!-- Page published by cmark-gfm begins here --><h1>Sucha's Blog ~ Archive for April, 2020</h1>
<p><a id="p0"></a></p>
<div class="date">20年4月18日 周六 23:48</div>
<h2>m_net 支持 pull style API 以及 timer</h2>
<p>意外的是 3 月份居然没写任何东西，那 4 月份就吹吹水吧。</p>
<h3>pull style API</h3>
<p>先说 <a href="https://github.com/lalawue/m_net">m_net</a> 为了在跟 LuaJIT 配合使用，改成了 pull style API，因为道听途说 stackoverflow 上的文章 <a href="https://stackoverflow.com/questions/12329128/luajit-ffi-callback-performance">LuaJIT FFI callback performance
</a>, 从 C 到 LuaJIT 的 callback 性能有很大的损失，大概会慢 27x 倍。</p>
<p>有了这个指标，修改为 pull style API 也不是难事，只是还想着同时支持 callback style API 来的。因为 pull style 在每个 mnet_poll() 循环，只能有一个事件抛出，但实际上就 socket 的事件来说，是可以多个的。</p>
<p>比如 chann 有数据读，但同时可写，这两个状态是可以同时存在的。那意味着这次 poll 中可以同时 callback 这两个事件。但在 pull style API 里面无法做到，这个是 API 的限制，但为了在 LuaJIT 中有更好的表现，这个特性只能放弃了。</p>
<h3>timer</h3>
<p>记得之前多次提过 timer，比如</p>
<ul>
<li><a href="../blog/2018-06.html#p1">Timer、FastLZ &amp; Erasure Codec</a></li>
<li><a href="../blog/2017-09.html#p0">有关 m_net 跨平台的小型网络库</a></li>
</ul>
<p>当然是更早时候看到了 rxi 的 <a href="https://github.com/rxi/dyad">dyad</a>，念念不忘。早先对 timer 需求没有那么大，甚至因为不是简单的 timer 需求，我将 timer 做到了更底层，将时间单位剥离，仅仅认为是一个数值关系、排序的库，虽然名字是叫 timer。</p>
<p>但一方面，不是所有的 timer 需求都那么复杂，另外，timer 单独出来有时候也很不方便，所以最后，同时因为有了之前实现某种 timer 的经验，我在 m_net 里面内置了一个，当然做了一些限制。</p>
<ul>
<li>一个 chann 只能带一个 repeat 类型的 timer，单位是 micro seconds</li>
<li>timer 事件的优先级最高，这个是因为 pull style API 的限制</li>
</ul>
<p>限制 timer 跟 chann 相关，是因为最终要将 timer 的回调做成 chann 的事件回调，或者 pull style API 里面的一个事件源，限制一个的原因也类似，不好在回调里面表示多个，没有那么复杂的需求需要多个，如果有需要，单靠这个 API 其实也是能实现的，比如分割成更小的单位。</p>
<p>第二个限制，timer 的优先级最高，是因为 mnet_poll() 拉取事件的时候，pull style API 只能有一个事件，这里其实不希望 timer 被调用得很频繁，但如果是被调用，一定不会被其他事件吃掉。</p>
<p>timer 具体的实现，其实是 skiplist，之前短暂尝试过 array 以及 qsort 配合，但是觉得内存使用上效率不大好，每次 timer fire 时间更新后，都需要做一次排序，array + qsort 的消耗，相比 skiplist 要大。</p>
<p>github 上拷贝了其他人 MIT LICENSE 的 skiplist，实现也只比 array + qsort 多 60 行而已，何乐而不为呢。</p>
<p>有了 skiplist 的加持，一个 timer 的更新，消耗只有 O (logn)，感觉还可以了。</p>
<div class="category"><a href="CategoryProgramming.html">CategoryProgramming</a> / <a href="2020-04.html#p0">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<!-- Page published by cmark-gfm ends here -->
  <div id="foot">2004-<script>var d = new
	Date();document.write(d.getFullYear())</script> &copy;
	Sucha. Powered by MarkdownProjectCompositor.
  </div>
  </div><!-- text -->
  <div id="sidebar">
  </div><!-- sidebar -->
  <script src="../js/prism.min.js" async="async"></script>
  <script src="../js/blog_sidebar.js"></script>
  </div> <!-- body -->
</body>
</html>